﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using Mindfor.Web.Data;
using NHibernate;
using NHibernate.Linq;
using Mindfor.Web.Models;

namespace Mindfor.Web.Modules.Pages
{
	/// <summary>
	/// Loads current page, page text, page title, keywords, description to ViewData.
	/// </summary>
	public class PageLoadFilter : IMvcFilter, IActionFilter
	{
		/// <summary>
		/// When implemented in a class, gets a value that indicates whether multiple filters are allowed.
		/// </summary>
		public bool AllowMultiple
		{
			get { return false; }
		}

		/// <summary>
		/// When implemented in a class, gets the filter order.
		/// </summary>
		public int Order
		{
			get { return 0; }
		}

		public void OnActionExecuting(ActionExecutingContext filterContext)
		{
			CmsController controller = filterContext.Controller as CmsController;
			ISession data = CmsApplication.DataProvider.GetCurrentSession();
			if (controller != null && data != null)
			{
				string mainActionName = null;
				Page currentPage = null;
				PageText currentPageText = null;

				// get current page, text, keywords, description
				int pageId = -1;
				object pageIdObj = filterContext.RouteData.Values["pageId"];
				object mainActionObj = filterContext.RouteData.Values["mainAction"];
				object mainActionPageIdObj = filterContext.RouteData.Values["mainActionPageId"];
				if (pageIdObj != null && int.TryParse(pageIdObj.ToString(), out pageId))
					mainActionName = null;
				else if (mainActionObj != null)
				{
					mainActionName = mainActionObj.ToString();
					if (mainActionPageIdObj != null)
						int.TryParse(mainActionPageIdObj.ToString(), out pageId);
				}
				
				if (pageId != -1)
				{
					currentPage = data.Get<Page>(pageId);
					if (currentPage != null && controller.Language != null)
						currentPageText = currentPage.GetText(controller.Language);
				}

				controller.ViewData["Global.MainActionName"] = mainActionName;
				controller.ViewData["Global.CurrentPage"] = currentPage;
				controller.ViewData["Global.CurrentPageText"] = currentPageText;
				bool isMainAction = String.IsNullOrEmpty(mainActionName);
				if (isMainAction)
				{
					if (currentPage != null && currentPage.Tags != null && currentPage.Tags.Count > 0)
						controller.ViewData.SetPageKeywords(currentPage.Tags.Select(t => t.Name).Merge(", "));
					if (currentPageText != null && currentPageText.Description != null)
						controller.ViewData.SetPageDescription(currentPageText.Description);
				}

				// check data provider access
				IEnumerable<Filter> filters = FilterProviders.Providers.GetFilters(filterContext.Controller.ControllerContext, filterContext.ActionDescriptor);
				bool hasAccessAttributes = filters.Any(r => r.Instance is CmsAuthorizeAttribute);
				if (!hasAccessAttributes && isMainAction &&
					currentPage != null && !currentPage.HasAccess(controller.User, true))
					filterContext.Result = new HttpStatusCodeResult(controller.User == null ? 401 : 403);

				// generate title
				if (filterContext.Result == null || filterContext.Result is ViewResultBase)
				{
					PageTitleCollection pageTitle = GeneratePageTitle(currentPage, controller.Language, controller.Url, filterContext.ActionDescriptor);
					controller.ViewData.SetPageTitle(pageTitle);
				}
			}
		}

		public void OnActionExecuted(ActionExecutedContext filterContext)
		{
		}

		/// <summary>
		/// Creates PageTitle items based on CustolTitleAttribute and data provider page values.
		/// </summary>
		/// <param name="executingAction">Currently executing action descriptor.</param>
		protected virtual PageTitleCollection GeneratePageTitle(Page currentPage, Language language, UrlHelper url, ActionDescriptor executingAction)
		{
			PageTitleCollection pageTitle = new PageTitleCollection();

			// generate page title from pages tree
			if (currentPage != null && language != null)
			{
				// create title node for every path info item
				foreach (PagePathItem item in currentPage.GetPathInfo(language))
				{
					// First take from PageTitle
					if (!String.IsNullOrEmpty(item.PageTitle) || !String.IsNullOrEmpty(item.HeadTitle))
					{
						PageTitleNode titleNode = new PageTitleNode(item.PageTitle, false);
						titleNode.HeadText = item.HeadTitle;
						titleNode.Url = url.Page(item.PageId);
						pageTitle.Add(titleNode);
					}
				}
			}

			return pageTitle;
		}
	}
}
